Skip to content

fix: redact decrypted config output from pod logs on config load failure - #40

Merged
eyevinn-developer[bot] merged 1 commit into
mainfrom
fix-config-log-redaction
Nov 6, 2026
Merged

eyevinn-developer[bot] merged 1 commit into
mainfrom
fix-config-log-redaction

Conversation

@eyevinn-developer

Copy link
Copy Markdown
Contributor

Summary

Fixes the leak of decrypted parameter-store values to pod logs when the CONFIG_SVC load fails in scripts/docker-entrypoint.sh.

  • New redact_config_log() helper, defined inside the extracted config block (the test's awk range). It replaces the literal values of OSC_ACCESS_TOKEN, CONFIG_API_KEY, GIT_TOKEN, GITHUB_TOKEN, then gh[pso]_ tokens, JWT-shaped strings and Basic credentials. Pure bash plus sed -E, no new dependency.
  • Non-zero exit path: logs the exit code and the redacted $config_err_output only; $config_env_output (the CLI stdout with decrypted values) is never printed.
  • The refresh-app-config hint now greps $config_err_output only, so a secret value containing 401 no longer triggers it.
  • "no valid export lines" path: logs the count and the NAME of each rejected export line (first 10, 64 chars each) plus values not logged, never the values.
  • Untouched: the Loading environment variables line, the Timed out line, the eval, the set -e comment, exit codes (124, config_exit, 1). The Low-severity items (root user, curl | bash, pip install gradio) are not touched.

Consumer impact

Log text only. The [CONFIG] Loading environment variables from config service line, the refresh-app-config hint text and all exit codes are unchanged. Audited by the triage in osaas-ai (instructions.ts rule 34, myapps.ts:4346), osaas-deploy-manager, osaas-app and osaas-e2e-tests: nothing parses the changed [CONFIG] ERROR lines. A consumer outside those repos (a tenant script reading its own logs) would not have been found.

Tests

Not wired to CI; run locally from the repo root.

bash -n scripts/docker-entrypoint.sh: OK

tests/test-entrypoint-config-load-failure.sh: 11 passed, 0 failed (7 existing plus new cases: secret on stdout during failure, invalid key name without its value, token/ghp/JWT redaction in stderr, stdout no longer drives the hint; the ok case also asserts qux is in neither stream).

Other suites: commit-info-exclude: All tests passed; credential-header-auth: 13 passed, 0 failed; credential-scrub: 6 passed, 0 failed; fragment-branch: 8 passed, 0 failed; setup-timeout: 7 passed, 0 failed; subpath: 7 passed, 0 failed.

What a human does next:

A prod sync-fork and remake of eyevinn-python-runner is birme's call; running apps pick the fix up on their next rebuild, and historical logs are not rewritten. The dev counterpart is agent-run after merge: .claude/scripts/dev-remake.sh https://github.com/Eyevinn/python-runner eyevinn-python-runner.

Closes #38

Lessons

A redaction helper has to live inside the block the test extracts with awk, otherwise it is command not found under test; and the realistic leak was not the failure branch but the "no valid export lines" branch, where a key like my-key made the whole decrypted stdout fail the grep and get echoed. Siblings php-runner and wasm-runner still print the same output and have no ticket.

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

Co-Authored-By: Claude <noreply@anthropic.com>

@eyevinn-pr-reviewer eyevinn-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Research Review

Verified

  • Premise: the only two prints of config_env_output (old lines 245/261) are replaced; grep -n config_env_output on the PR head shows the remaining uses are only the empty check, the export grep and the new name-only extraction. Directions match the architect triage on #38.
  • Helper placement: redact_config_log() sits after the # Load environment variables from config service comment, inside the range the test's awk extracts, so it is defined under test.
  • Pinned CLI behaviour (stdout = export KEY='value', stderr = err.message) is as stated in the triage (@osaas/cli@4.35.0); no new external API used (bash + sed -E).
  • Reproduced locally on head 025d5f6: bash -n OK; all 7 tests/test-entrypoint-*.sh pass (config-load-failure 11/0, credential-header-auth 13/0, credential-scrub 6/0, fragment-branch 8/0, setup-timeout 7/0, subpath 7/0, commit-info-exclude all passed), matching the PR body.

Adjacent Stubs Detected

  • None (no TODO/FIXME/HACK/undefined patterns in the touched script).

Orphaned Files Detected

  • None. Both touched files are entry scripts/tests invoked directly.

Escape Hatch Coverage

  • No new terminal-rejection branch: exit codes (124, config_exit, 1) and the fatal path are unchanged. Passing path remains covered (ok case, now also asserting qux is in neither stream).

Object Shape Verification

  • No spreads of fetched objects (bash only).

Contract diff

  • No request handler or timeout changed (checked scripts/docker-entrypoint.sh, tests/test-entrypoint-config-load-failure.sh). Only stderr log text changes; the Loading environment variables line, refresh-app-config hint text and exit codes are unchanged.

Impact Analysis

  • Blast radius: python-runner pod log text on config-load failure only.
  • Downstream consumers: osaas-ai (instructions.ts rule 34, myapps.ts:4346) key on the unchanged Loading line and hint; audit per the triage and PR body, with the stated coverage limit (tenant scripts outside the searched repos).
  • Coordinated changes needed: none. Prod sync-fork/remake is birme's call, stated in the PR.
  • Breaking change risk: low.

Risks Not Tested

  • Tests are not wired to CI (no checks on the branch); I ran them locally only.
  • Redaction is pattern-based; a secret in stderr that is not one of the four runner tokens, a gh[pso]_ token, a JWT or Basic credential would pass through. Stdout is never printed, so this only concerns CLI error messages.
  • Sibling runners php-runner and wasm-runner still print the same output; noted in the PR Lessons, out of scope here.

Research Suggestions

  • Consider a follow-up ticket for php-runner and wasm-runner (the PR Lessons say none exists).

Verdict

No blocking issues found.


Reviewed by PR Research Validator. This review checks whether code is based on verified sources rather than assumptions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Raw config-to-env output (decrypted secrets) is echoed to pod logs on failure

2 participants